﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using awsomeSyntezator.PipeLine;


namespace awsomeSyntezator
{
    public class Sound
    {
        private static FMOD.RESULT result;
        private static FMOD.System system;
        private static FMOD.Channel channel;
        private FMOD.CREATESOUNDEXINFO info;

        private bool engineEnabled = false;
        private bool soundCreated = false;
        public Pipe pipe;
        public FMOD.Sound sound = null;
        public static Options options;

        public Sound()
        {
            pipe = new Pipe();

            if (!engineEnabled)
            {
                result = FMOD.Factory.System_Create(ref system);
                result = system.init(1, FMOD.INITFLAGS.NORMAL, IntPtr.Zero);

                info = new FMOD.CREATESOUNDEXINFO();
                info.cbsize = Marshal.SizeOf(info);
                info.numchannels = 1;
                info.format = FMOD.SOUND_FORMAT.PCM16;
                info.defaultfrequency = Options.rate;
				info.length = (uint)(Options.rate * 8.0 * Options.time / 1000.0);

                engineEnabled = true;
            }
        }

        public void play()
        {
            system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel);
        }


        public void createSound()
        {
            if(!soundCreated)
            {
                result = system.createSound((string)null, (FMOD.MODE._2D | FMOD.MODE.SOFTWARE | FMOD.MODE.OPENUSER | FMOD.MODE.LOOP_OFF), ref info, ref sound);
                soundCreated = true;
            }

            IntPtr ptr1 = new IntPtr();
            IntPtr ptr2 = new IntPtr();
            uint len1 = 0;
            uint len2 = 0;

            List<double> sample = new List<double>();

            for (int i = 0; i < Options.samples; i++)
            {
                sample.Add(pipe.getSample(i, 0));
            }
            double scale = Int16.MaxValue/Math.Max(Math.Abs(sample.Min()),sample.Max());


            result = sound.@lock(0, (uint) Options.samples, ref ptr1, ref ptr2, ref len1, ref len2);
            unsafe
            {
                short* dataPtr = (short*)ptr1;  //wskaźnik do pojedynczych próbek
                for (int i = 0; i < sample.Count; i++)
                {
                    dataPtr[i] = (short)Math.Round(sample[i]*scale);
                }
            }
            result = sound.unlock(ptr1, ptr2, len1, len2);
        }

        public void playOnLive()
        {
            createSound();
            play();
        }
    }
}
